// Includes
#include "Sprite.h"
#include "TextureLoaders.h"		// Texture loader functions

#include <iostream>		// C++ I/O stream header
#ifdef _WIN32
#include <windows.h>		// Include windows header on the windows platform
#endif
#include <GL/gl.h>		// OpenGL header

using namespace std;

namespace EraAstral
{
	namespace graphics
	{
		// Sprite class constructor
		Sprite::Sprite()
		{
			// Set null pointers
			m_texture = NULL;
			
			// Set initial position and scale
			m_position = new Vector2();
			m_scale = new Vector2(1.0f);
			// Set inital layer value
			m_layer = 0.5f;
		}
		
		// Sprite class destructor
		Sprite::~Sprite()
		{
			// Delete texture
			if (m_texture != NULL)
				delete m_texture;
				
			// Delete position
			delete m_position;
			delete m_scale;
		}
		
		// Loads a texture for the sprite from a file
		int Sprite::LoadTexture(const char *fileName)
		{		
			// Determine extension of the file
			int dotPosition = -1;
			char *lowerCaseFileName = new char[strlen(fileName) + 1];
			// Add string end symbol
			lowerCaseFileName[strlen(fileName)] = '\0';
			// Loop through to find dot
			for (unsigned int i = 0; i < strlen(fileName); i++)
			{
				// Convert to lower case letters
				lowerCaseFileName[i] = tolower(fileName[i]);	
			
				if (fileName[i] == '.')
					dotPosition = i;
			}
			
			// Check if no dot was found
			if (dotPosition == -1)
			{
				cout << "Error loading texture file. No file extension found." << endl;
				// Free memory used for lower case file name
				delete[] lowerCaseFileName;
				return 1;
			}
			
			// Check extension
			if (strncmp(lowerCaseFileName + dotPosition, ".jpg", 4) == 0 ||
						strncmp(lowerCaseFileName + dotPosition, ".jpeg", 5) == 0)
			{
				cout << "Texture file identified as JPEG." << endl;
				// Load JPEG texture file
				m_texture = LoadJPG(fileName);
			}
			else if (strncmp(lowerCaseFileName + dotPosition, ".bmp", 4) == 0)
			{
				cout << "Texture file identified as BMP." << endl;
				// Load BMP texture file
				m_texture = LoadBMP(fileName);
			}
			else if (strncmp(lowerCaseFileName + dotPosition, ".png", 4) == 0)
			{
				cout << "Texture file identified as PNG." << endl;
				// Load PNG texture file
				m_texture = LoadPNG(fileName);
			}
			else
			{
				// Unknown texture file format
				cout << "Error loading texture: File format not recognized." << endl;
				return 2;
			}
			
			// Check if texture was loaded successfully
			if (m_texture == NULL)
			{
				// Error while loading
				cout << "Could not load texture from file " << fileName << endl;
				return 3;
			}
			else
				// Commit changes and generate OpenGL texture
				m_texture->Commit();
				
			// Free memory used for lower case file name
			delete[] lowerCaseFileName;
			
			// Return successfully
			return 0;
		}
		
		// Draws the sprite
		void Sprite::Draw()
		{
			// Check if texture exists
			if (m_texture == NULL)
				return;

			// Push OpenGL matrix
			glPushMatrix();		
		
			// Calculate half width and height of texture
			float halfWidth = (float)m_texture->GetWidth() / 2.0f;
			float halfHeight = (float)m_texture->GetHeight() / 2.0f;
			
			if (m_texture != NULL)
			{
				// Apply texture
				glEnable(GL_TEXTURE_2D);
				m_texture->Bind();
			}	
			else
				return;
			
			// Translate by position
			glTranslatef(m_position->X, m_position->Y, 0.0f);
			// Scale texture
			glScalef(m_scale->X, m_scale->Y, 0.0f);
			
			// Begin OpenGL drawing sequence
			glBegin(GL_QUADS);
				// Draw quad for texture
				glTexCoord2f(1.0f, 1.0f);
				glVertex2f(halfWidth, -halfHeight);
				
				glTexCoord2f(1.0f, 0.0f);
				glVertex2f(halfWidth, halfHeight);
				
				glTexCoord2f(0.0f, 0.0f);
				glVertex2f(-halfWidth, halfHeight);
				
				glTexCoord2f(0.0f, 1.0f);
				glVertex2f(-halfWidth, -halfHeight);
			// End OpenGL drawing sequence
			glEnd();
			
			// Clear bound texture
			glBindTexture(GL_TEXTURE_2D, 0);
			
			// Pop OpenGL matrix
			glPopMatrix();
		}
		
		// Gets the position of the sprite
		Vector2 *Sprite::GetPosition() const
		{
			return m_position;
		}
		
		// Sets the position of the sprite
		void Sprite::SetPosition(const Vector2& position)
		{
			// Set components
			m_position->X = position.X;
			m_position->Y = position.Y;
		}
		
		// Gets the position of the sprite
		Vector2 *Sprite::GetScale() const
		{
			return m_scale;
		}
		
		// Sets the position of the sprite
		void Sprite::SetScale(const Vector2& scale)
		{
			// Set components
			m_scale->X = scale.X;
			m_scale->Y = scale.Y;
		}
		
		// Gets the layer value of the sprite
		float Sprite::GetLayer() const
		{
			return m_layer;
		}
		
		// Sets the layer value of the sprite
		void Sprite::SetLayer(float layer)
		{
			m_layer = layer;
		}
		
		// Sets the texture of the sprite
		void Sprite::SetTexture(Texture *texture)
		{
			m_texture = texture;
		}
	}
}
